﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace LocalizationTest.Tools
{
  public partial class DrawingPanelContainer : UserControl
  {
    Point newPosition;
    int newColor = 250;
    DockStyle newDockStyle = DockStyle.Fill;
    Point globalMouseDownPoint;
    bool mouseIsDown = false;
    ResizeType resizeType;
    string currentPanelID = "";
    

    public Dictionary<string, DrawingPanel> panelIDs = new Dictionary<string, DrawingPanel>();

    public DrawingPanelContainer()
    {
      InitializeComponent();
      newPosition = new Point(100, 100);
    }
    public Panel AddPanel(string panelID)
    {
      DrawingPanel drawingPanel = new DrawingPanel(panelIDs.Keys.Count);
      drawingPanel.Location = newPosition;
      drawingPanel.Panel.BackColor = Color.FromArgb(newColor, newColor, newColor);
      newColor = (int)(0.9 * newColor);
      newPosition = new Point(newPosition.X + 100, newPosition.Y + 100);
      drawingPanel.Location = newPosition;
      drawingPanel.Panel.MouseMove += new MouseEventHandler(panel_MouseMove);
      drawingPanel.Panel.MouseDown += new MouseEventHandler(panel_MouseDown);
      drawingPanel.Panel.MouseUp += new MouseEventHandler(panel_MouseUp);
      drawingPanel.Panel.DoubleClick += new EventHandler(panel_DoubleClick);
      drawingPanel.LinkLabelHide.LinkClicked += new LinkLabelLinkClickedEventHandler(LinkLabelHide_LinkClicked);
      drawingPanel.PanelID = panelID;
      drawingPanel.Panel.Dock = newDockStyle;
      string oldPanelState = ConfigurationTool.Configuration.ReadConfigurationEntry(drawingPanel.PanelID, "");
      if (oldPanelState == "")
      {
        if (newDockStyle == DockStyle.Fill) newDockStyle = DockStyle.Right;
        else if (newDockStyle == DockStyle.Right) newDockStyle = DockStyle.Bottom;
        else if (newDockStyle == DockStyle.Bottom) newDockStyle = DockStyle.None;
      }
      else
      {
        drawingPanel.RestoreFromString(oldPanelState);
        newDockStyle = DockStyle.None;
      }
      this.Controls.Add(drawingPanel.Panel);
      panelIDs.Add(panelID, drawingPanel);
      BringPanelToFront(drawingPanel.Panel);
      return drawingPanel.Panel;
    }

    public string GetPanelID(Panel panel)
    {
      string panelID = "";
      foreach (string key in panelIDs.Keys)
      {
        if (panelIDs[key].Panel == panel) panelID = key;
      }
      return panelID;
    }

    void LinkLabelHide_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    {
    }

    void panel_DoubleClick(object sender, EventArgs e)
    {
      Panel panel = (sender as Panel);
      if (panel.Dock != DockStyle.Fill)
      {
        panel.Dock = DockStyle.Fill;
        BringPanelToFront(panel);
      }
      else
      {
        panel.Dock = DockStyle.None;
        panel.Width = this.Width / 5;
        panel.Height = this.Height / 5;
        panel.Location = new Point(Width / 2 - Width / 10, Height / 2 - Height / 10);
      }
      ConfigurationTool.Configuration.WriteConfigurationEntry(GetPanelID(panel), panelIDs[GetPanelID(panel)].SaveStateToString());
    }

    void panel_MouseDown(object sender, MouseEventArgs e)
    {
      Panel senderAsPanel = (sender as Panel);
      Point globalLocation = new Point(senderAsPanel.Location.X + e.Location.X, senderAsPanel.Location.Y + e.Location.Y);
//      DebugTextTool.Output("mouseDown panel: " + globalLocation);
      this.Parent.Invalidate();
      mouseIsDown = true;
      resizeType = GetResizeType(e.Location, senderAsPanel);
      globalMouseDownPoint = globalLocation;
//      BringPanelToFront(senderAsPanel);
//      senderAsPanel.BringToFront();
    }
    void panel_MouseUp(object sender, MouseEventArgs e)
    {
      Panel senderAsPanel = (sender as Panel);
      Point globalLocation = new Point(senderAsPanel.Location.X + e.Location.X, senderAsPanel.Location.Y + e.Location.Y);
//      DebugTextTool.Output("mouseDown panel: " + globalLocation);
      this.Parent.Invalidate();
      mouseIsDown = false;
      senderAsPanel.Invalidate();
      foreach (DrawingPanel drawingPanel in panelIDs.Values)
      {
        drawingPanel.Panel.Invalidate();
      }
    }
    void panel_MouseMove(object sender, MouseEventArgs e)
    {
      Panel senderAsPanel = (sender as Panel);
      senderAsPanel.Focus();
      Point globalLocation = new Point(senderAsPanel.Location.X + e.Location.X, senderAsPanel.Location.Y + e.Location.Y);
//      DebugTextTool.Output("mousemove panel: " + globalLocation);
      this.Parent.Invalidate();
      SetCursor(e.Location, senderAsPanel);
      MoveAndResize(globalLocation, senderAsPanel);
      globalMouseDownPoint = globalLocation;
      currentPanelID = GetPanelID(senderAsPanel);
    }

    
    private void DrawingPanelContainer_MouseMove(object sender, MouseEventArgs e)
    {
      this.Cursor = Cursors.Default;
//      DebugTextTool.Output("mousemove: " + e.Location);
      this.Parent.Invalidate();
    }

    private void DrawingPanelContainer_MouseDown(object sender, MouseEventArgs e)
    {
//      DebugTextTool.Output("mousedown: " + e.Location);
      this.Parent.Invalidate();
    }

    private void SetCursor(Point localLocation, Panel panel)
    {
      ResizeType resizeType = GetResizeType(localLocation, panel);

      if (resizeType == ResizeType.left || resizeType == ResizeType.right) this.Cursor = Cursors.SizeWE;
      else if (resizeType == ResizeType.top || resizeType == ResizeType.bottom) this.Cursor = Cursors.SizeNS;
      else if (resizeType == ResizeType.topLeft || resizeType == ResizeType.bottomRight) this.Cursor = Cursors.SizeNWSE;
      else if (resizeType == ResizeType.topRight || resizeType == ResizeType.bottomLeft) this.Cursor = Cursors.SizeNESW;
      else this.Cursor = Cursors.SizeAll;
    }

    enum ResizeType { topLeft, topRight, bottomLeft, bottomRight, top, bottom, left, right, move };

    private ResizeType GetResizeType(Point localLocation, Panel panel)
    {
      if (panel.Dock != DockStyle.Fill)
      {
        if (localLocation.X < 10 && localLocation.Y < 10) return ResizeType.topLeft;
        if (localLocation.X < 10 && localLocation.Y > panel.Height - 10) return ResizeType.bottomLeft;
        if (localLocation.X > panel.Width - 10 && localLocation.Y > panel.Height - 10) return ResizeType.bottomRight;
        if (localLocation.X > panel.Width - 10 && localLocation.Y < 10) return ResizeType.topRight;
        if (localLocation.X < 10) return ResizeType.left;
        if (localLocation.Y < 10) return ResizeType.top;
        if (localLocation.X > panel.Width - 10) return ResizeType.right;
        if (localLocation.Y > panel.Height - 10) return ResizeType.bottom;
      }
      return ResizeType.move;
    }

    private Point MoveAndResize(Point globalLocation, Panel panel)
    {
      if (mouseIsDown)
      {
        Point signOfWidthChange = new Point();
        if (resizeType == ResizeType.right || resizeType == ResizeType.topRight || resizeType == ResizeType.bottomRight) signOfWidthChange.X = 1;
        if (resizeType == ResizeType.left || resizeType == ResizeType.topLeft || resizeType == ResizeType.bottomLeft) signOfWidthChange.X = -1;
        if (resizeType == ResizeType.top || resizeType == ResizeType.topRight || resizeType == ResizeType.topLeft) signOfWidthChange.Y = -1;
        if (resizeType == ResizeType.bottom || resizeType == ResizeType.bottomLeft || resizeType == ResizeType.bottomRight) signOfWidthChange.Y = 1;
        Point movedDistance = new Point(globalLocation.X - globalMouseDownPoint.X, globalLocation.Y - globalMouseDownPoint.Y);
        int newWidth = Math.Max(30, panel.Width + signOfWidthChange.X * movedDistance.X);
        int newHeight = Math.Max(30, panel.Height + signOfWidthChange.Y * movedDistance.Y);
        if (newWidth == 30 && resizeType != ResizeType.move) movedDistance.X = 0;
        if (newHeight == 30 && resizeType != ResizeType.move) movedDistance.Y = 0;
        switch (resizeType)
        {
          case ResizeType.move:
            bool wasDocked = false;
            if (panel.Dock == DockStyle.Left && movedDistance.X > 0) { int panelX = panel.Location.X; panel.Dock = DockStyle.None; panel.Height = this.Height / 5; panel.Location = new Point(panelX + movedDistance.X, globalLocation.Y - this.Height / 10); wasDocked = true; }
            if (panel.Dock == DockStyle.Right && movedDistance.X < 0) { int panelX = panel.Location.X; panel.Dock = DockStyle.None; panel.Height = this.Height / 5; panel.Location = new Point(panelX + movedDistance.X, globalLocation.Y - this.Height / 10); wasDocked = true; }
            if (panel.Dock == DockStyle.Top && movedDistance.Y > 0) { int panelY = panel.Location.Y; panel.Dock = DockStyle.None; panel.Width = this.Width / 5; panel.Location = new Point(globalLocation.X - this.Width / 10, panelY + movedDistance.Y); wasDocked = true; }
            if (panel.Dock == DockStyle.Bottom && movedDistance.Y < 0) { int panelY = panel.Location.Y; panel.Dock = DockStyle.None; panel.Width = this.Width / 5; panel.Location = new Point(globalLocation.X - this.Width / 10, panelY + movedDistance.Y); wasDocked = true; }
            if (panel.Dock == DockStyle.Fill) {panel.Dock = DockStyle.None; panel.Location = panel.Location = new Point(globalLocation.X - this.Width / 10, globalLocation.Y - this.Height / 10); wasDocked = true; }
            if (!wasDocked)
            {
//              BringPanelToFront(panel);
              panel.BringToFront();
            }
            panel.Location = new Point(panel.Location.X + movedDistance.X, panel.Location.Y + movedDistance.Y);
            break;
          case ResizeType.left:
            panel.Location = new Point(panel.Location.X + movedDistance.X, panel.Location.Y);
            panel.Width = newWidth;
            break;
          case ResizeType.right:
            panel.Width = newWidth;
            break;
          case ResizeType.top:
            panel.Location = new Point(panel.Location.X, panel.Location.Y + movedDistance.Y);
            panel.Height = newHeight;
            break;
          case ResizeType.bottom:
            panel.Height = newHeight;
            break;
          case ResizeType.topLeft:
            panel.Location = new Point(panel.Location.X + movedDistance.X, panel.Location.Y + movedDistance.Y);
            panel.Width = newWidth;
            panel.Height = newHeight;
            break;
          case ResizeType.bottomRight:
            panel.Width = newWidth;
            panel.Height = newHeight;
            break;
          case ResizeType.topRight:
            panel.Location = new Point(panel.Location.X, panel.Location.Y + movedDistance.Y);
            panel.Width = newWidth;
            panel.Height = newHeight;
            break;
          case ResizeType.bottomLeft:
            panel.Location = new Point(panel.Location.X + movedDistance.X, panel.Location.Y);
            panel.Width = newWidth;
            panel.Height = newHeight;
            break;
        }
        if (panel.Dock == DockStyle.None)
        {
          ClipLocation(panel);
          SetDockStyleByLocation(panel);
        }
        ConfigurationTool.Configuration.WriteConfigurationEntry(GetPanelID(panel), panelIDs[GetPanelID(panel)].SaveStateToString());
        panel.Invalidate();
      }//if (mouseIsDown)
      else
      {
//        SetCursor(globalLocation);
      }
      return globalLocation;
    }

    private void ClipLocation(Panel panel)
    {
      if (panel.Location.X < -1) panel.Location = new Point(-1, panel.Location.Y);
      if (panel.Location.Y < -1) panel.Location = new Point(panel.Location.X, -1);
      if (panel.Location.X + panel.Width > this.Width) panel.Location = new Point(this.Width - panel.Width, panel.Location.Y);
      if (panel.Location.Y + panel.Height > this.Height) panel.Location = new Point(panel.Location.X, this.Height - panel.Height);
    }

    private void SetDockStyleByLocation(Panel panel)
    {
      if (panel.Location.X < 0) panel.Dock = DockStyle.Left;
      else if (panel.Location.Y < 0) panel.Dock = DockStyle.Top;
      else if (panel.Location.X + panel.Width >= this.Width) panel.Dock = DockStyle.Right;
      else if (panel.Location.Y + panel.Height >= this.Height) panel.Dock = DockStyle.Bottom;
      if (panel.Dock != DockStyle.None)
      {
        panel.SendToBack();
        mouseIsDown = false;
      }
    }

    public void BringPanelToFront(Panel panel)
    {
      panel.BringToFront();
      foreach (string key in panelIDs.Keys)
      {
        if (panelIDs[key].LinkLabelHide.Text != "hide" || panelIDs[key].Panel.Dock == DockStyle.None || panelIDs[key].Panel.Dock == DockStyle.Fill) 
          panelIDs[key].Panel.BringToFront();
      }
    }

    public void ZoomInCurrentPanel()
    {
      if(currentPanelID == "") return;
      panelIDs[currentPanelID].ZoomIn();
      ConfigurationTool.Configuration.WriteConfigurationEntry(currentPanelID, panelIDs[currentPanelID].SaveStateToString());
    }

    public void ZoomOutCurrentPanel()
    {
      if (currentPanelID == "") return;
      panelIDs[currentPanelID].ZoomOut();
      ConfigurationTool.Configuration.WriteConfigurationEntry(currentPanelID, panelIDs[currentPanelID].SaveStateToString());
    }

    public void ResetZoom()
    {
      if (currentPanelID == "") return;
      panelIDs[currentPanelID].ResetZoom();
      ConfigurationTool.Configuration.WriteConfigurationEntry(currentPanelID, panelIDs[currentPanelID].SaveStateToString());
    }

  }
}
